/*
 * Copyright (C) 2021 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *    1. Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the
 *       distribution.
 *    3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
 *       its contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifdef CONFIG_BLEHOST
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>

#include "ohos_bt_def.h"
#include "ohos_bt_gatt.h"
#include "ohos_bt_gatt_server.h"

#include "framework/bt_ctrl.h"

#include <stddef.h>
#include <stdlib.h>
#include <string.h>

#include <zephyr.h>

#include <settings/settings.h>

#include <bluetooth/hci.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>
#include "ble/sys/util.h"
#include "ble/sys/byteorder.h"

#include "common/framework/bt_ctrl.h"

#include "xr_ohos_utils.h"

#if (defined(CONFIG_BT_BROADCASTER) && defined(CONFIG_BT_EXT_ADV))
#error "error must not CONFIG_BT_EXT_ADV"
#endif

#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)

/*************************** for adapt **********************************/
static BtGattCallbacks xrble_hal_gatt_callback;

/*************************** from xr ble **********************************/
static bool no_settings_load = 1;

uint8_t selected_id = BT_ID_DEFAULT;

#if defined(CONFIG_BT_CONN)
struct bt_conn *default_conn;

/* Connection context for BR/EDR legacy pairing in sec mode 3 */
static struct bt_conn *pairing_conn;

static struct bt_le_oob oob_local;
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
static struct bt_le_oob oob_remote;
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR) */
#endif /* CONFIG_BT_CONN */

#define NAME_LEN 30

#define KEY_STR_LEN 33

/*
* Based on the maximum number of parameters for HCI_LE_Generate_DHKey
* See BT Core Spec V5.2 Vol. 4, Part E, section 7.8.37
*/
#define HCI_CMD_MAX_PARAM 65

#if defined(CONFIG_BT_EXT_ADV)
#if defined(CONFIG_BT_BROADCASTER)
static uint8_t selected_adv;
struct bt_le_ext_adv *adv_sets[CONFIG_BT_EXT_ADV_MAX_ADV_SET];
#endif /* CONFIG_BT_BROADCASTER */
#endif /* CONFIG_BT_EXT_ADV */

#if defined(CONFIG_BT_OBSERVER) || defined(CONFIG_BT_USER_PHY_UPDATE)
static const char *phy2str(uint8_t phy)
{
	switch (phy) {
	case 0:
		return "No packets";
	case BT_GAP_LE_PHY_1M:
		return "LE 1M";
	case BT_GAP_LE_PHY_2M:
		return "LE 2M";
	case BT_GAP_LE_PHY_CODED:
		return "LE Coded";
	default:
		return "Unknown";
	}
}
#endif

#if defined(CONFIG_BT_OBSERVER)
static bool data_cb(struct bt_data *data, void *user_data)
{
	char *name = user_data;

	switch (data->type) {
	case BT_DATA_NAME_SHORTENED:
	case BT_DATA_NAME_COMPLETE:
		memcpy(name, data->data, MIN(data->data_len, NAME_LEN - 1));
		return false;
	default:
		return true;
	}
}

static void scan_recv(const struct bt_le_scan_recv_info *info,
		      struct net_buf_simple *buf)
{
	char le_addr[BT_ADDR_LE_STR_LEN];
	char name[NAME_LEN];

	(void)memset(name, 0, sizeof(name));

	bt_data_parse(buf, data_cb, name);

	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
	XR_BLE_DBG("[DEVICE]: %s, AD evt type %u, RSSI %i %s "
		   "C:%u S:%u D:%d SR:%u E:%u Prim: %s, Secn: %s, "
		   "Interval: 0x%04x (%u ms), SID: 0x%x",
		   le_addr, info->adv_type, info->rssi, name,
		   (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0,
		   (info->adv_props & BT_GAP_ADV_PROP_SCANNABLE) != 0,
		   (info->adv_props & BT_GAP_ADV_PROP_DIRECTED) != 0,
		   (info->adv_props & BT_GAP_ADV_PROP_SCAN_RESPONSE) != 0,
		   (info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) != 0,
		   phy2str(info->primary_phy), phy2str(info->secondary_phy),
		   info->interval, info->interval * 5 / 4, info->sid);
	if (xrble_hal_gatt_callback.scanResultCb) {
		BtScanResultData scanResultdata;
		SCAN_RESULT_DATA_PARASE(&scanResultdata, info);
		xrble_hal_gatt_callback.scanResultCb(&scanResultdata);
	}
}

static void scan_timeout(void)
{
	XR_BLE_DBG("Scan timeout");
}
#endif /* CONFIG_BT_OBSERVER */

#if defined(CONFIG_BT_EXT_ADV)
#if defined(CONFIG_BT_BROADCASTER)
static void adv_sent(struct bt_le_ext_adv *adv,
		     struct bt_le_ext_adv_sent_info *info)
{
	XR_BLE_DBG("Advertiser[%d] %p sent %d", bt_le_ext_adv_get_index(adv),
		   adv, info->num_sent);
}

static void adv_scanned(struct bt_le_ext_adv *adv,
			struct bt_le_ext_adv_scanned_info *info)
{
	char str[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(info->addr, str, sizeof(str));

	XR_BLE_DBG("Advertiser[%d] %p scanned by %s",
		   bt_le_ext_adv_get_index(adv), adv, str);
}
#endif /* CONFIG_BT_BROADCASTER */

#if defined(CONFIG_BT_PERIPHERAL)
static void adv_connected(struct bt_le_ext_adv *adv,
			  struct bt_le_ext_adv_connected_info *info)
{
	char str[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(info->conn), str, sizeof(str));

	XR_BLE_DBG("Advertiser[%d] %p connected by %s",
		   bt_le_ext_adv_get_index(adv), adv, str);
}
#endif /* CONFIG_BT_PERIPHERAL */
#endif /* CONFIG_BT_EXT_ADV */

void conn_addr_str(struct bt_conn *conn, char *addr, size_t len)
{
	struct bt_conn_info info;

	if (bt_conn_get_info(conn, &info) < 0) {
		addr[0] = '\0';
		return;
	}

	switch (info.type) {
#if defined(CONFIG_BT_BREDR)
	case BT_CONN_TYPE_BR:
		bt_addr_to_str(info.br.dst, addr, len);
		break;
#endif
	case BT_CONN_TYPE_LE:
		bt_addr_le_to_str(info.le.dst, addr, len);
		break;
	}
}

static void print_le_oob(struct bt_le_oob *oob)
{
	char addr[BT_ADDR_LE_STR_LEN];
	char c[KEY_STR_LEN];
	char r[KEY_STR_LEN];

	bt_addr_le_to_str(&oob->addr, addr, sizeof(addr));

	bin2hex(oob->le_sc_data.c, sizeof(oob->le_sc_data.c), c, sizeof(c));
	bin2hex(oob->le_sc_data.r, sizeof(oob->le_sc_data.r), r, sizeof(r));

	XR_BLE_DBG("OOB data:");
	XR_BLE_DBG("%-29s %-32s %-32s", "addr", "random", "confirm");
	XR_BLE_DBG("%29s %32s %32s", addr, r, c);
}

static void connected(struct bt_conn *conn, uint8_t err)
{
	char addr[BT_ADDR_LE_STR_LEN];

	conn_addr_str(conn, addr, sizeof(addr));

	if (err) {
		XR_BLE_ERR("Failed to connect to %s (0x%02x)", addr, err);
		goto done;
	}

	XR_BLE_DBG("Connected: %s", addr);

	if (!default_conn) {
		default_conn = bt_conn_ref(conn);
	}

done:
	/* clear connection reference for sec mode 3 pairing */
	if (pairing_conn) {
		bt_conn_unref(pairing_conn);
		pairing_conn = NULL;
	}
}

static void disconnected(struct bt_conn *conn, uint8_t reason)
{
	char addr[BT_ADDR_LE_STR_LEN];

	conn_addr_str(conn, addr, sizeof(addr));
	XR_BLE_DBG("Disconnected: %s (reason 0x%02x)", addr, reason);

	if (default_conn == conn) {
		bt_conn_unref(default_conn);
		default_conn = NULL;
	}
}

static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
{
	XR_BLE_DBG("LE conn  param req: int (0x%04x, 0x%04x) lat %d"
		   " to %d",
		   param->interval_min, param->interval_max, param->latency,
		   param->timeout);

	return true;
}

static void le_param_updated(struct bt_conn *conn, uint16_t interval,
			     uint16_t latency, uint16_t timeout)
{
	XR_BLE_DBG("LE conn param updated: int 0x%04x lat %d "
		   "to %d",
		   interval, latency, timeout);
}

#if defined(CONFIG_BT_SMP)
static void identity_resolved(struct bt_conn *conn, const bt_addr_le_t *rpa,
			      const bt_addr_le_t *identity)
{
	char addr_identity[BT_ADDR_LE_STR_LEN];
	char addr_rpa[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(identity, addr_identity, sizeof(addr_identity));
	bt_addr_le_to_str(rpa, addr_rpa, sizeof(addr_rpa));

	XR_BLE_DBG("Identity resolved %s -> %s", addr_rpa, addr_identity);
}
#endif

#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
static const char *security_err_str(enum bt_security_err err)
{
	switch (err) {
	case BT_SECURITY_ERR_SUCCESS:
		return "Success";
	case BT_SECURITY_ERR_AUTH_FAIL:
		return "Authentication failure";
	case BT_SECURITY_ERR_PIN_OR_KEY_MISSING:
		return "PIN or key missing";
	case BT_SECURITY_ERR_OOB_NOT_AVAILABLE:
		return "OOB not available";
	case BT_SECURITY_ERR_AUTH_REQUIREMENT:
		return "Authentication requirements";
	case BT_SECURITY_ERR_PAIR_NOT_SUPPORTED:
		return "Pairing not supported";
	case BT_SECURITY_ERR_PAIR_NOT_ALLOWED:
		return "Pairing not allowed";
	case BT_SECURITY_ERR_INVALID_PARAM:
		return "Invalid parameters";
	case BT_SECURITY_ERR_UNSPECIFIED:
		return "Unspecified";
	default:
		return "Unknown";
	}
}

static void security_changed(struct bt_conn *conn, bt_security_t level,
			     enum bt_security_err err)
{
	char addr[BT_ADDR_LE_STR_LEN];

	conn_addr_str(conn, addr, sizeof(addr));

	if (!err) {
		XR_BLE_DBG("Security changed: %s level %u", addr, level);
	} else {
		XR_BLE_DBG("Security failed: %s level %u "
			   "reason: %s (%d)",
			   addr, level, security_err_str(err), err);
	}
}
#endif

#if defined(CONFIG_BT_REMOTE_INFO)
static const char *ver_str(uint8_t ver)
{
	const char *const str[] = {
		"1.0b", "1.1", "1.2", "2.0", "2.1", "3.0",
		"4.0",	"4.1", "4.2", "5.0", "5.1",
	};

	if (ver < ARRAY_SIZE(str)) {
		return str[ver];
	}

	return "unknown";
}

static void remote_info_available(struct bt_conn *conn,
				  struct bt_conn_remote_info *remote_info)
{
	struct bt_conn_info info;

	bt_conn_get_info(conn, &info);

	if (IS_ENABLED(CONFIG_BT_REMOTE_VERSION)) {
		XR_BLE_DBG("Remote LMP version %s (0x%02x) subversion 0x%04x "
			   "manufacturer 0x%04x",
			   ver_str(remote_info->version), remote_info->version,
			   remote_info->subversion, remote_info->manufacturer);
	}

	if (info.type == BT_CONN_TYPE_LE) {
		uint8_t features[8];
		char features_str[2 * sizeof(features) + 1];

		sys_memcpy_swap(features, remote_info->le.features,
				sizeof(features));
		bin2hex(features, sizeof(features), features_str,
			sizeof(features_str));
		XR_BLE_DBG("LE Features: 0x%s ", features_str);
	}
}
#endif /* defined(CONFIG_BT_REMOTE_INFO) */

#if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)
void le_data_len_updated(struct bt_conn *conn,
			 struct bt_conn_le_data_len_info *info)
{
	XR_BLE_DBG("LE data len updated: TX (len: %d time: %d)"
		   " RX (len: %d time: %d)",
		   info->tx_max_len, info->tx_max_time, info->rx_max_len,
		   info->rx_max_time);
}
#endif

#if defined(CONFIG_BT_USER_PHY_UPDATE)
void le_phy_updated(struct bt_conn *conn, struct bt_conn_le_phy_info *info)
{
#if defined(CONFIG_BT_OBSERVER)
	XR_BLE_DBG("LE PHY updated: TX PHY %s, RX PHY %s",
		   phy2str(info->tx_phy), phy2str(info->rx_phy));
#endif
}
#endif
#if defined(CONFIG_BT_CONN)

static struct bt_conn_cb conn_callbacks = {
	.connected = connected,
	.disconnected = disconnected,
	.le_param_req = le_param_req,
	.le_param_updated = le_param_updated,
#if defined(CONFIG_BT_SMP)
	.identity_resolved = identity_resolved,
#endif
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
	.security_changed = security_changed,
#endif
#if defined(CONFIG_BT_REMOTE_INFO)
	.remote_info_available = remote_info_available,
#endif
#if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)
	.le_data_len_updated = le_data_len_updated,
#endif
#if defined(CONFIG_BT_USER_PHY_UPDATE)
	.le_phy_updated = le_phy_updated,
#endif
};
#endif /* CONFIG_BT_CONN */

#if defined(CONFIG_BT_OBSERVER)
static struct bt_le_scan_cb scan_callbacks = {
	.recv = scan_recv,
	.timeout = scan_timeout,
};
#endif /* defined(CONFIG_BT_OBSERVER) */

#if defined(CONFIG_BT_EXT_ADV)
#if defined(CONFIG_BT_BROADCASTER)
static struct bt_le_ext_adv_cb adv_callbacks = {
	.sent = adv_sent,
	.scanned = adv_scanned,
#if defined(CONFIG_BT_PERIPHERAL)
	.connected = adv_connected,
#endif /* CONFIG_BT_PERIPHERAL */
};
#endif /* CONFIG_BT_BROADCASTER */
#endif /* CONFIG_BT_EXT_ADV */

/************************************io cap******************************************/

static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey)
{
	char addr[BT_ADDR_LE_STR_LEN];
	char passkey_str[7];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	snprintk(passkey_str, 7, "%06u", passkey);

	XR_BLE_DBG("Passkey for %s: %s", addr, passkey_str);
}

static void auth_passkey_confirm(struct bt_conn *conn, unsigned int passkey)
{
	char addr[BT_ADDR_LE_STR_LEN];
	char passkey_str[7];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	snprintk(passkey_str, 7, "%06u", passkey);

	XR_BLE_DBG("Confirm passkey for %s: %s", addr, passkey_str);
}

static void auth_passkey_entry(struct bt_conn *conn)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	XR_BLE_DBG("Enter passkey for %s", addr);
}

static void auth_cancel(struct bt_conn *conn)
{
	char addr[BT_ADDR_LE_STR_LEN];

	conn_addr_str(conn, addr, sizeof(addr));

	XR_BLE_DBG("Pairing cancelled: %s", addr);

	/* clear connection reference for sec mode 3 pairing */
	if (pairing_conn) {
		bt_conn_unref(pairing_conn);
		pairing_conn = NULL;
	}
}

static void auth_pairing_confirm(struct bt_conn *conn)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	XR_BLE_DBG("Confirm pairing for %s", addr);
}

#if !defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY)
static const char *oob_config_str(int oob_config)
{
	switch (oob_config) {
	case BT_CONN_OOB_LOCAL_ONLY:
		return "Local";
	case BT_CONN_OOB_REMOTE_ONLY:
		return "Remote";
	case BT_CONN_OOB_BOTH_PEERS:
		return "Local and Remote";
	case BT_CONN_OOB_NO_DATA:
	default:
		return "no";
	}
}
#endif /* !defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY) */

static void auth_pairing_oob_data_request(struct bt_conn *conn,
					  struct bt_conn_oob_info *oob_info)
{
	char addr[BT_ADDR_LE_STR_LEN];
	struct bt_conn_info info;
	int err;

	err = bt_conn_get_info(conn, &info);
	if (err) {
		return;
	}

#if !defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY)
	if (oob_info->type == BT_CONN_OOB_LE_SC) {
		struct bt_le_oob_sc_data *oobd_local =
			oob_info->lesc.oob_config != BT_CONN_OOB_REMOTE_ONLY ?
				      &oob_local.le_sc_data :
				      NULL;
		struct bt_le_oob_sc_data *oobd_remote =
			oob_info->lesc.oob_config != BT_CONN_OOB_LOCAL_ONLY ?
				      &oob_remote.le_sc_data :
				      NULL;

		if (oobd_remote &&
		    bt_addr_le_cmp(info.le.remote, &oob_remote.addr)) {
			bt_addr_le_to_str(info.le.remote, addr, sizeof(addr));
			XR_BLE_DBG("No OOB data available for remote %s", addr);
			bt_conn_auth_cancel(conn);
			return;
		}

		if (oobd_local &&
		    bt_addr_le_cmp(info.le.local, &oob_local.addr)) {
			bt_addr_le_to_str(info.le.local, addr, sizeof(addr));
			XR_BLE_DBG("No OOB data available for local %s", addr);
			bt_conn_auth_cancel(conn);
			return;
		}

		bt_le_oob_set_sc_data(conn, oobd_local, oobd_remote);

		bt_addr_le_to_str(info.le.dst, addr, sizeof(addr));
		XR_BLE_DBG("Set %s OOB SC data for %s, ",
			   oob_config_str(oob_info->lesc.oob_config), addr);
		return;
	}
#endif /* CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY */

	bt_addr_le_to_str(info.le.dst, addr, sizeof(addr));
	XR_BLE_DBG("Legacy OOB TK requested from remote %s", addr);
}

static void auth_pairing_complete(struct bt_conn *conn, bool bonded)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	XR_BLE_DBG("%s with %s", bonded ? "Bonded" : "Paired", addr);
}

static void auth_pairing_failed(struct bt_conn *conn, enum bt_security_err err)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	XR_BLE_DBG("Pairing failed with %s reason: %s (%d)", addr,
		   security_err_str(err), err);
}

#if defined(CONFIG_BT_BREDR)
static void auth_pincode_entry(struct bt_conn *conn, bool highsec)
{
	char addr[BT_ADDR_STR_LEN];
	struct bt_conn_info info;

	if (bt_conn_get_info(conn, &info) < 0) {
		return;
	}

	if (info.type != BT_CONN_TYPE_BR) {
		return;
	}

	bt_addr_to_str(info.br.dst, addr, sizeof(addr));

	if (highsec) {
		XR_BLE_DBG("Enter 16 digits wide PIN code for %s", addr);
	} else {
		XR_BLE_DBG("Enter PIN code for %s", addr);
	}

	/*
	* Save connection info since in security mode 3 (link level enforced
	* security) PIN request callback is called before connected callback
	*/
	if (!default_conn && !pairing_conn) {
		pairing_conn = bt_conn_ref(conn);
	}
}
#endif

#if defined(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)
enum bt_security_err
pairing_accept(struct bt_conn *conn,
	       const struct bt_conn_pairing_feat *const feat)
{
	XR_BLE_DBG("Remote pairing features: "
		   "IO: 0x%02x, OOB: %d, AUTH: 0x%02x, Key: %d, "
		   "Init Kdist: 0x%02x, Resp Kdist: 0x%02x",
		   feat->io_capability, feat->oob_data_flag, feat->auth_req,
		   feat->max_enc_key_size, feat->init_key_dist,
		   feat->resp_key_dist);

	return BT_SECURITY_ERR_SUCCESS;
}
#endif /* CONFIG_BT_SMP_APP_PAIRING_ACCEPT */

void bond_deleted(uint8_t id, const bt_addr_le_t *peer)
{
	char addr[BT_ADDR_STR_LEN];

	bt_addr_le_to_str(peer, addr, sizeof(addr));
	XR_BLE_DBG("Bond deleted for %s, id %u", addr, id);
}

static struct bt_conn_auth_cb auth_cb_display = {
	.passkey_display = auth_passkey_display,
	.passkey_entry = NULL,
	.passkey_confirm = NULL,
#if defined(CONFIG_BT_BREDR)
	.pincode_entry = auth_pincode_entry,
#endif
	.oob_data_request = NULL,
	.cancel = auth_cancel,
	.pairing_confirm = auth_pairing_confirm,
	.pairing_failed = auth_pairing_failed,
	.pairing_complete = auth_pairing_complete,
#if defined(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)
	.pairing_accept = pairing_accept,
#endif
	.bond_deleted = bond_deleted,
};

static struct bt_conn_auth_cb auth_cb_display_yes_no = {
	.passkey_display = auth_passkey_display,
	.passkey_entry = NULL,
	.passkey_confirm = auth_passkey_confirm,
#if defined(CONFIG_BT_BREDR)
	.pincode_entry = auth_pincode_entry,
#endif
	.oob_data_request = NULL,
	.cancel = auth_cancel,
	.pairing_confirm = auth_pairing_confirm,
	.pairing_failed = auth_pairing_failed,
	.pairing_complete = auth_pairing_complete,
#if defined(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)
	.pairing_accept = pairing_accept,
#endif
	.bond_deleted = bond_deleted,
};

static struct bt_conn_auth_cb auth_cb_input = {
	.passkey_display = NULL,
	.passkey_entry = auth_passkey_entry,
	.passkey_confirm = NULL,
#if defined(CONFIG_BT_BREDR)
	.pincode_entry = auth_pincode_entry,
#endif
	.oob_data_request = NULL,
	.cancel = auth_cancel,
	.pairing_confirm = auth_pairing_confirm,
	.pairing_failed = auth_pairing_failed,
	.pairing_complete = auth_pairing_complete,
#if defined(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)
	.pairing_accept = pairing_accept,
#endif
	.bond_deleted = bond_deleted,
};

static struct bt_conn_auth_cb auth_cb_confirm = {
#if defined(CONFIG_BT_BREDR)
	.pincode_entry = auth_pincode_entry,
#endif
	.oob_data_request = NULL,
	.cancel = auth_cancel,
	.pairing_confirm = auth_pairing_confirm,
	.pairing_failed = auth_pairing_failed,
	.pairing_complete = auth_pairing_complete,
#if defined(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)
	.pairing_accept = pairing_accept,
#endif
	.bond_deleted = bond_deleted,
};

static struct bt_conn_auth_cb auth_cb_all = {
	.passkey_display = auth_passkey_display,
	.passkey_entry = auth_passkey_entry,
	.passkey_confirm = auth_passkey_confirm,
#if defined(CONFIG_BT_BREDR)
	.pincode_entry = auth_pincode_entry,
#endif
	.oob_data_request = auth_pairing_oob_data_request,
	.cancel = auth_cancel,
	.pairing_confirm = auth_pairing_confirm,
	.pairing_failed = auth_pairing_failed,
	.pairing_complete = auth_pairing_complete,
#if defined(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)
	.pairing_accept = pairing_accept,
#endif
	.bond_deleted = bond_deleted,
};

static struct bt_conn_auth_cb auth_cb_oob = {
	.passkey_display = NULL,
	.passkey_entry = NULL,
	.passkey_confirm = NULL,
#if defined(CONFIG_BT_BREDR)
	.pincode_entry = NULL,
#endif
	.oob_data_request = auth_pairing_oob_data_request,
	.cancel = auth_cancel,
	.pairing_confirm = NULL,
	.pairing_failed = auth_pairing_failed,
	.pairing_complete = auth_pairing_complete,
#if defined(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)
	.pairing_accept = pairing_accept,
#endif
	.bond_deleted = bond_deleted,
};

static struct bt_conn_auth_cb auth_cb_status = {
	.pairing_failed = auth_pairing_failed,
	.pairing_complete = auth_pairing_complete,
#if defined(CONFIG_BT_SMP_APP_PAIRING_ACCEPT)
	.pairing_accept = pairing_accept,
#endif
};

/************************************io cap******************************************/

static void bt_ready(int err)
{
	if (err) {
		XR_BLE_ERR("Bluetooth init failed (err %d)", err);
		return;
	}

	XR_BLE_DBG("Bluetooth initialized");

	if (IS_ENABLED(CONFIG_SETTINGS) && !no_settings_load) {
		settings_load();
		XR_BLE_DBG("Settings Loaded");
	}

	if (IS_ENABLED(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY)) {
		bt_set_oob_data_flag(true);
	}

#if defined(CONFIG_BT_OBSERVER)
	bt_le_scan_cb_register(&scan_callbacks);
#endif

#if defined(CONFIG_BT_CONN)
	default_conn = NULL;

	bt_conn_cb_register(&conn_callbacks);
#endif /* CONFIG_BT_CONN */

#if 0
// #if defined(CONFIG_BT_PER_ADV_SYNC)
#error "CONFIG_BT_PER_ADV_SYNC off"
	bt_le_per_adv_sync_cb_register(&per_adv_sync_cb);
#endif /* CONFIG_BT_PER_ADV_SYNC */
}

/**
 * @brief Initializes the Bluetooth protocol stack.
 *
 * @return Returns {@link OHOS_BT_STATUS_SUCCESS} if the Bluetooth protocol stack is initialized;
 * returns an error code defined in {@link BtStatus} otherwise.
 * @since 6
 */
int InitBtStack(void)
{
	// do nothing or do some gatt
	return 0;
}

/**
 * @brief Enables the Bluetooth protocol stack.
 *
 * @return Returns {@link OHOS_BT_STATUS_SUCCESS} if the Bluetooth protocol stack is enabled;
 * returns an error code defined in {@link BtStatus} otherwise.
 * @since 6
 */
int EnableBtStack(void)
{
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	int err;

	err = bt_ctrl_enable();
	if (err) {
		XR_BLE_ERR("Bluetooth Controller init failed (err %d)", err);
		return err;
	}

	err = bt_enable(bt_ready);
	if (err) {
		XR_BLE_ERR("Bluetooth init failed (err %d)", err);
	}

	return err;
}

/**
 * @brief Disables the Bluetooth protocol stack.
 *
 * @return Returns {@link OHOS_BT_STATUS_SUCCESS} if the Bluetooth protocol stack is disabled;
 * returns an error code defined in {@link BtStatus} otherwise.
 * @since 6
 */
int DisableBtStack(void)
{
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	int err;

#if defined(CONFIG_BT_CONN)
	default_conn = NULL;

	bt_conn_cb_unregister(&conn_callbacks);
#endif /* CONFIG_BT_CONN */

#if defined(CONFIG_BT_OBSERVER)
	bt_le_scan_cb_unregister(&scan_callbacks);
#endif

	if (IS_ENABLED(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY)) {
		bt_set_oob_data_flag(false);
	}

	err = bt_disable();
	if (err) {
		XR_BLE_ERR("Bluetooth deinit failed (err %d)", err);
		return err;
	} else {
		XR_BLE_DBG("Bluetooth deinitialized");
	}

	err = bt_ctrl_disable();
	if (err) {
		XR_BLE_ERR("Bluetooth controller deinit failed (err %d)", err);
	} else {
		XR_BLE_DBG("Bluetooth controller deinitialized");
	}

	return err;
}

/**
 * @brief Sets the Bluetooth device name.
 *
 * @param name Indicates the pointer to the name to set.
 * @param len Indicates the length of the name to set.
 * @return Returns {@link OHOS_BT_STATUS_SUCCESS} if the Bluetooth device name is set;
 * returns an error code defined in {@link BtStatus} otherwise.
 * @since 6
 */
int SetDeviceName(const char *name, unsigned int len)
{
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	int err;
	err = bt_set_name(name);
	if (err) {
		XR_BLE_ERR("Unable to set name %s (err %d)", name, err);
		return err;
	}
	return 0;
}

/**
 * @brief Sets advertising data.
 *
 * @param advId Indicates the advertisement ID, which is allocated by the upper layer of the advertiser.
 * @param data Indicates the pointer to the advertising data. For details, see {@link BleConfigAdvData}.
 * @return Returns {@link OHOS_BT_STATUS_SUCCESS} if advertising data is set;
 * returns an error code defined in {@link BtStatus} otherwise.
 * @since 6
 */
int BleSetAdvData(int advId, const BleConfigAdvData *data)
{
#if defined(CONFIG_BT_BROADCASTER)
#if defined(CONFIG_BT_EXT_ADV)
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	int err;
	int selected_adv = advId;
	struct bt_le_ext_adv *adv = adv_sets[selected_adv];
	struct bt_data ad[8] = {};
	size_t ad_len = 0;
	struct bt_data sd[8] = {};
	size_t sd_len = 0;

	err = OHOS_ADV_DATA_2_XRBLE_ADV_DATA(data, ad, &ad_len, sd, &sd_len);
	if (err) {
		XR_BLE_ERR("Failed to set advertising set data (%d)", err);
		goto faild;
	}
	err = bt_le_ext_adv_set_data(adv, ad_len > 0 ? ad : NULL, ad_len,
				     sd_len > 0 ? sd : NULL, sd_len);
	if (err) {
		XR_BLE_ERR("Failed to set advertising set data (%d)", err);
		goto faild;
	}
	if (xrble_hal_gatt_callback.advDataCb) {
		xrble_hal_gatt_callback.advDataCb(advId,
						  OHOS_BT_STATUS_SUCCESS);
	}
	return 0;
faild:
	if (xrble_hal_gatt_callback.advDataCb) {
		xrble_hal_gatt_callback.advDataCb(advId, OHOS_BT_STATUS_FAIL);
	}
	return 0;
#else /* LEGACY_ADV */
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	int err;
	struct bt_data ad[8] = {};
	size_t ad_len = 0;
	struct bt_data sd[8] = {};
	size_t sd_len = 0;

	err = OHOS_ADV_DATA_2_XRBLE_ADV_DATA(data, ad, &ad_len, sd, &sd_len);
	if (err) {
		XR_BLE_ERR("Failed to set advertising data (%d)", err);
		goto faild;
	}
	err = bt_le_adv_update_data(ad_len > 0 ? ad : NULL, ad_len,
				    sd_len > 0 ? sd : NULL, sd_len);
	if (err) {
		XR_BLE_ERR("Failed to set advertising data (%d)", err);
		goto faild;
	}
	if (xrble_hal_gatt_callback.advDataCb) {
		xrble_hal_gatt_callback.advDataCb(advId,
						  OHOS_BT_STATUS_SUCCESS);
	}
	return 0;
faild:
	if (xrble_hal_gatt_callback.advDataCb) {
		xrble_hal_gatt_callback.advDataCb(advId, OHOS_BT_STATUS_FAIL);
	}
	return 0;
#endif /* CONFIG_BT_EXT_ADV */
#endif /* CONFIG_BT_BROADCASTER */
	return 0;
}

/**
 * @brief Starts advertising.
 *
 * @param advId Indicates the advertisement ID, which is allocated by the upper layer of the advertiser.
 * @param param Indicates the pointer to the advertising parameters. For details, see {@link BleAdvParams}.
 * @return Returns {@link OHOS_BT_STATUS_SUCCESS} if advertising is started;
 * returns an error code defined in {@link BtStatus} otherwise.
 * @since 6
 */
int BleStartAdv(int advId, const BleAdvParams *param)
{
#if defined(CONFIG_BT_BROADCASTER)
#if defined(CONFIG_BT_EXT_ADV)
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	int selected_adv = advId;
	struct bt_le_ext_adv *adv = adv_sets[selected_adv];
	struct bt_le_adv_param adv_param = {};
	struct bt_le_ext_adv_start_param ext_param;
	uint8_t num_events = 0;
	int32_t timeout = 0;
	int err;

	if (!adv) {
		XR_BLE_ERR("Advertiser[%d] not created", selected_adv);
		goto faild;
		// return -EINVAL;
	}
	err = OHOS_ADV_PARAM_2_XRBLE_LEGACY_ADV_PARAM(&param, &adv_param);
	if (err) {
		XR_BLE_ERR("Failed to update advertiser set param (%d)", err);
		goto faild;
	}
	err = bt_le_ext_adv_update_param(adv, &adv_param);
	if (err) {
		XR_BLE_ERR("Failed to update advertising set param (%d)", err);
		goto faild;
	}
	ext_param.timeout = param->duration;
	// ext_param.num_events = num_events;
	err = bt_le_ext_adv_start(adv, &ext_param);
	if (err) {
		XR_BLE_ERR("Failed to start advertising set (%d)", err);
		goto faild;
	}

	XR_BLE_ERR("Advertiser[%d] %p set started", selected_adv, adv);
	if (xrble_hal_gatt_callback.advEnableCb) {
		xrble_hal_gatt_callback.advEnableCb(
			advId, OHOS_BT_STATUS_SUCCESS); //ohoscallback
	}
	return 0;
faild:
	if (xrble_hal_gatt_callback.advEnableCb) {
		xrble_hal_gatt_callback.advEnableCb(
			advId, OHOS_BT_STATUS_FAIL); //ohoscallback
	}
	return 0;
#else /* LEGACY_ADV */
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	int err;
	struct bt_le_adv_param adv_param = {};
	OHOS_ADV_PARAM_2_XRBLE_LEGACY_ADV_PARAM(param, &adv_param);

	err = bt_le_adv_start(&adv_param, NULL, 0, NULL, 0);
	if (err < 0) {
		XR_BLE_ERR("Failed to start advertising (err %d)", err);
		goto faild;
		return err;
	} else {
		XR_BLE_DBG("Advertising started");
	}
	if (xrble_hal_gatt_callback.advEnableCb) {
		xrble_hal_gatt_callback.advEnableCb(
			advId, OHOS_BT_STATUS_SUCCESS); //ohoscallback
	}
	return 0;
faild:
	if (xrble_hal_gatt_callback.advEnableCb) {
		xrble_hal_gatt_callback.advEnableCb(
			advId, OHOS_BT_STATUS_FAIL); //ohoscallback
	}
	return 0;
#endif /* CONFIG_BT_EXT_ADV */
#endif /* CONFIG_BT_BROADCASTER */
}

/**
 * @brief Stops advertising.
 *
 * @param advId Indicates the advertisement ID, which is allocated by the upper layer of the advertiser.
 * @return Returns {@link OHOS_BT_STATUS_SUCCESS} if advertising is stopped;
 * returns an error code defined in {@link BtStatus} otherwise.
 * @since 6
 */
int BleStopAdv(int advId)
{
#if defined(CONFIG_BT_BROADCASTER)
#if defined(CONFIG_BT_EXT_ADV)
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	int selected_adv = advId;
	struct bt_le_ext_adv *adv = adv_sets[selected_adv];
	int err;

	if (!adv) {
		XR_BLE_DBG("Advertiser[%d] not created", selected_adv);
		return -EINVAL;
	}

	err = bt_le_ext_adv_stop(adv);
	if (err) {
		XR_BLE_DBG("Failed to stop advertising set (%d)", err);
		goto faild;
		return -ENOEXEC;
	}
	XR_BLE_DBG("Advertiser set stopped");
	if (xrble_hal_gatt_callback.advDisableCb) {
		xrble_hal_gatt_callback.advDisableCb(
			advId, OHOS_BT_STATUS_SUCCESS); //ohoscallback
	}
	return 0;
faild:
	if (xrble_hal_gatt_callback.advDisableCb) {
		xrble_hal_gatt_callback.advDisableCb(
			advId, OHOS_BT_STATUS_FAIL); //ohoscallback
	}
	return 0;
#else /* LEGACY_ADV */
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	if (bt_le_adv_stop() < 0) {
		XR_BLE_ERR("Failed to stop advertising");
		goto faild;
	} else {
		XR_BLE_DBG("Advertising stopped");
	}
	if (xrble_hal_gatt_callback.advDisableCb) {
		xrble_hal_gatt_callback.advDisableCb(
			advId, OHOS_BT_STATUS_SUCCESS); //ohoscallback
	}
	return 0;
faild:
	if (xrble_hal_gatt_callback.advDisableCb) {
		xrble_hal_gatt_callback.advDisableCb(
			advId, OHOS_BT_STATUS_FAIL); //ohoscallback
	}
	return 0;
#endif /* CONFIG_BT_EXT_ADV */
#endif /* CONFIG_BT_BROADCASTER */
	return 0;
}

/**
 * @brief Updates advertising parameters.
 *
 * @param advId Indicates the advertisement ID, which is allocated by the upper layer of the advertiser.
 * @param param Indicates the pointer to the advertising parameters. For details, see {@link BleAdvParams}.
 * @return Returns {@link OHOS_BT_STATUS_SUCCESS} if advertising parameters are updated;
 * returns an error code defined in {@link BtStatus} otherwise.
 * @since 6
 */
int BleUpdateAdv(int advId, const BleAdvParams *param)
{
#if defined(CONFIG_BT_BROADCASTER)
#if defined(CONFIG_BT_EXT_ADV)
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	int selected_adv = advId;
	struct bt_le_ext_adv *adv = adv_sets[selected_adv];
	struct bt_le_adv_param adv_param = {};
	int err;

	if (!OHOS_ADV_PARAM_2_XRBLE_LEGACY_ADV_PARAM(param, &adv_param)) {
		XR_BLE_ERR("Failed to update advertiser set param (%d)", err);
		goto faild;
	}

	err = bt_le_ext_adv_update_param(adv, &adv_param);
	if (err) {
		XR_BLE_ERR("Failed to update advertiser set (%d)", err);
		goto faild;
	}
	if (xrble_hal_gatt_callback.advUpdateCb) {
		xrble_hal_gatt_callback.advUpdateCb(advId,
						    OHOS_BT_STATUS_SUCCESS);
	}
	return 0;
faild:
	if (xrble_hal_gatt_callback.advUpdateCb) {
		xrble_hal_gatt_callback.advUpdateCb(advId, OHOS_BT_STATUS_FAIL);
	}
	return 0;
#else /* LEGACY_ADV */
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	//todoornottodo
#endif /* CONFIG_BT_EXT_ADV */
#endif /* CONFIG_BT_BROADCASTER */
	return 0;
}
/**
 * @brief Sets the secure I/O capability mode.
 *
 * @param mode Indicates the capability mode to set. For details, see {@link BleIoCapMode}.
 * @return Returns {@link OHOS_BT_STATUS_SUCCESS} if the capability mode is set;
 * returns an error code defined in {@link BtStatus} otherwise.
 * @since 6
 */
int BleSetSecurityIoCap(BleIoCapMode mode) //todo check
{
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	int err;

	switch (mode) {
	case OHOS_BLE_IO_CAP_OUT: // display only
		err = bt_conn_auth_cb_register(&auth_cb_display);
		break;
	case OHOS_BLE_IO_CAP_IO: // YES NO
		err = bt_conn_auth_cb_register(&auth_cb_display_yes_no);
		break;
	case OHOS_BLE_IO_CAP_IN: // KeyboardOnly 0-9   YES NO
		err = bt_conn_auth_cb_register(&auth_cb_input);
		break;
	case OHOS_BLE_IO_CAP_NONE: //no I/O capability
		err = bt_conn_auth_cb_register(NULL);
		break;
	case OHOS_BLE_IO_CAP_KBDISP: //KeyboardDisplay
		err = bt_conn_auth_cb_register(&auth_cb_confirm);
		break;
	default:
		err = bt_conn_auth_cb_register(NULL);
		break;
	}
	if (err) {
		XR_BLE_ERR("set io cap faild");
	}
	XR_BLE_ERR("BleSetSecurityIoCap mode = [%d]", mode);
	return 0;
}

/**
 * @brief Sets the authentication mode for secure connection requests.
 *
 * @param mode Indicates the authentication mode to set. For details, see {@link BleAuthReqMode}.
 * @return Returns {@link OHOS_BT_STATUS_SUCCESS} if the authentication mode is set;
 * returns an error code defined in {@link BtStatus} otherwise.
 * @since 6
 */
int BleSetSecurityAuthReq(BleAuthReqMode mode)
{
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	int err, sec;
	struct bt_conn_info info;

	if (!default_conn || (bt_conn_get_info(default_conn, &info) < 0)) {
		XR_BLE_ERR("Not connected");
		return -ENOEXEC;
	}

	switch (mode) {
	case OHOS_BLE_AUTH_NO_BOND: /** No bonding */
		sec |= BT_SECURITY_L1;
		bt_set_bondable(false);
		break;
	case OHOS_BLE_AUTH_BOND: /** Bonding */
		sec |= BT_SECURITY_L2;
		bt_set_bondable(true);
		break;
	case OHOS_BLE_AUTH_REQ_MITM: /** MITM only */
		sec |= BT_SECURITY_L3;
		break;
	case OHOS_BLE_AUTH_REQ_SC_ONLY: /** Secure connection only */
		sec |= BT_SECURITY_L2;
		break;
	case OHOS_BLE_AUTH_REQ_SC_BOND: /** Secure connection and bonding */
		sec |= BT_SECURITY_L2;
		bt_set_bondable(true);
		break;
	case OHOS_BLE_AUTH_REQ_SC_MITM: /** Secure connection and MITM */
		sec |= BT_SECURITY_L3;
		break;
	case OHOS_BLE_AUTH_REQ_SC_MITM_BOND: /** Secure connection, MITM, and bonding */
		sec |= BT_SECURITY_L3;
		sec |= BT_SECURITY_FORCE_PAIR;
		bt_set_bondable(true);
		break;
	default:
		break;
	}

	if ((info.type == BT_CONN_TYPE_LE &&
	     (sec < BT_SECURITY_L1 || sec > BT_SECURITY_L4))) {
		XR_BLE_ERR("Invalid LE security level (%d)", sec);
		return -ENOEXEC;
	}

	err = bt_conn_set_security(default_conn, sec);
	if (err) {
		XR_BLE_ERR("Setting security failed (err %d)", err);
	}
	XR_BLE_DBG("Setting security mode (%d)", mode);

	return 0;
}

/**
 * @brief Responds to a secure connection request.
 *
 * @param bdAddr Indicates the address of the device that sends the request.
 * @param accept Specifies whether to accept the request. The value <b>true</b> means to accept the request,
 * and <b>false</b> means to reject the request.
 * @return Returns {@link OHOS_BT_STATUS_SUCCESS} if the request is responded to;
 * returns an error code defined in {@link BtStatus} otherwise.
 * @since 6
 */
int BleGattSecurityRsp(BdAddr bdAddr, bool accept) //todo
{
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	return 0;
}

/**
 * @brief Obtains the device MAC address.
 *
 * @param mac Indicates the pointer to the device MAC address.
 * @param len Indicates the length of the device MAC address.
 * @return Returns {@link OHOS_BT_STATUS_SUCCESS} if the device MAC address is obtained;
 * returns an error code defined in {@link BtStatus} otherwise.
 * @since 6
 */
int ReadBtMacAddr(unsigned char *mac, unsigned int len)
{
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	int selected_id = 0;
	bt_addr_le_t addrs[CONFIG_BT_ID_MAX];
	size_t i, count = CONFIG_BT_ID_MAX;

	bt_id_get(addrs, &count);

	bt_addr_le_to_str(&addrs[selected_id], mac, len);
	XR_BLE_DBG("[*] %u: %s", selected_id, mac);

	for (i = 0; i < count; i++) {
		char addr_str[BT_ADDR_LE_STR_LEN];
		bt_addr_le_to_str(&addrs[i], addr_str, sizeof(addr_str));
		XR_BLE_DBG("%s%u: %s", i == selected_id ? "*" : " ", i,
			   addr_str);
	}
	return 0;
}

static struct bt_le_scan_param scan_param = {
	.type = BT_LE_SCAN_TYPE_ACTIVE,
	.options = BT_LE_SCAN_OPT_FILTER_DUPLICATE,
	.interval = BT_GAP_SCAN_FAST_INTERVAL,
	.window = BT_GAP_SCAN_FAST_WINDOW,
	.timeout = 0,
};

/**
 * @brief Sets scan parameters.
 *
 * @param clientId Indicates the client ID, which is obtained during client registration.
 * @param param Indicates the pointer to the scan parameters. For details, see {@link BleScanParams}.
 * @return Returns {@link OHOS_BT_STATUS_SUCCESS} if the scan parameters are set;
 * returns an error code defined in {@link BtStatus} otherwise.
 * @since 6
 */
int BleSetScanParameters(int clientId, BleScanParams *param)
{
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	int err;
	err = OHOS_SCAN_PARAM_2_XRBLE_SCAN_PARAM(param, &scan_param);
	if (err) {
		XR_BLE_ERR("Bluetooth set scan param failed (err %d)", err);
		goto faild;
		// return err;
	} else {
		XR_BLE_DBG("Bluetooth scan param success");
	}
	if (xrble_hal_gatt_callback.scanParamSetCb) {
		xrble_hal_gatt_callback.scanParamSetCb(clientId,
						       OHOS_BT_STATUS_SUCCESS);
	}
	return 0;
faild:
	if (xrble_hal_gatt_callback.scanParamSetCb) {
		xrble_hal_gatt_callback.scanParamSetCb(clientId,
						       OHOS_BT_STATUS_FAIL);
	}
	return 0;
}

/**
 * @brief Starts a scan.
 *
 * @return Returns {@link OHOS_BT_STATUS_SUCCESS} if the scan is started;
 * returns an error code defined in {@link BtStatus} otherwise.
 * @since 6
 */
int BleStartScan(void)
{
#if defined(CONFIG_BT_OBSERVER)
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	int err;
	err = bt_le_scan_start(&scan_param, NULL);
	if (err) {
		XR_BLE_ERR("Bluetooth set scan failed "
			   "(err %d)",
			   err);
		return err;
	} else {
		XR_BLE_DBG("Bluetooth scan enabled");
	}
#endif /* CONFIG_BT_OBSERVER */
	return 0;
}

/**
 * @brief Stops a scan.
 *
 * @return Returns {@link OHOS_BT_STATUS_SUCCESS} if the scan is stopped;
 * returns an error code defined in {@link BtStatus} otherwise.
 * @since 6
 */
int BleStopScan(void)
{
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	int err;

	err = bt_le_scan_stop();
	if (err) {
		XR_BLE_ERR("Stopping scanning failed (err %d)", err);
		return err;
	} else {
		XR_BLE_DBG("Scan successfully stopped");
	}

	return 0;
}

/**
 * @brief Registers GATT callbacks.
 *
 * @param func Indicates the pointer to the callbacks to register. For details, see {@link BtGattCallbacks}.
 * @return Returns {@link OHOS_BT_STATUS_SUCCESS} if the GATT callbacks are registered;
 * returns an error code defined in {@link BtStatus} otherwise.
 * @since 6
 */
int BleGattRegisterCallbacks(BtGattCallbacks *func)
{
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	if (!func) {
		return OHOS_BT_STATUS_FAIL;
	}
	if (func->advEnableCb) {
		xrble_hal_gatt_callback.advEnableCb = func->advEnableCb;
	}
	if (func->advDisableCb) {
		xrble_hal_gatt_callback.advDisableCb = func->advDisableCb;
	}
	if (func->advDataCb) {
		xrble_hal_gatt_callback.advDataCb = func->advDataCb;
	}
	if (func->advUpdateCb) {
		xrble_hal_gatt_callback.advUpdateCb = func->advUpdateCb;
	}
	if (func->securityRespondCb) {
		xrble_hal_gatt_callback.securityRespondCb =
			func->securityRespondCb; //todo
	}
	if (func->scanResultCb) {
		xrble_hal_gatt_callback.scanResultCb = func->scanResultCb;
	}
	if (func->scanParamSetCb) {
		xrble_hal_gatt_callback.scanParamSetCb = func->scanParamSetCb;
	}
	return 0;
}

/**
 * @brief Sets advertising data and parameters and starts advertising.
 *
 * This function is available for system applications only. \n
 *
 * @param advId Indicates the pointer to the advertisement ID.
 * @param rawData Indicates the advertising data. For details, see {@link StartAdvRawData}.
 * @param advParam Indicates the advertising parameters. For details, see {@link BleAdvParams}.
 * @return Returns {@link OHOS_BT_STATUS_SUCCESS} if the operation is successful;
 * returns an error code defined in {@link BtStatus} otherwise.
 * @since 6
 */
int BleStartAdvEx(int *advId, const StartAdvRawData rawData, BleAdvParams param)
{
#if defined(CONFIG_BT_BROADCASTER)
// #if 0
#if defined(CONFIG_BT_EXT_ADV)
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	struct bt_le_adv_param adv_param = {};
	struct bt_le_ext_adv *adv;
	uint8_t adv_index;
	int err;

	BleConfigAdvData config_adv_data;

	config_adv_data.advData = rawData.advData;
	config_adv_data.advLength = rawData.advDataLen;
	config_adv_data.scanRspData = rawData.rspData;
	config_adv_data.scanRspLength = rawData.rspDataLen;

	if (!OHOS_ADV_PARAM_2_XRBLE_LEGACY_ADV_PARAM(&param, &adv_param)) {
		XR_BLE_ERR("Failed to update advertiser set param (%d)", err);
		return -ENOEXEC;
	}

	err = bt_le_ext_adv_create(&param, &adv_callbacks, &adv);
	if (err) {
		XR_BLE_ERR("Failed to create advertiser set (%d)", err);
		return -ENOEXEC;
	}

	adv_index = bt_le_ext_adv_get_index(adv);
	adv_sets[adv_index] = adv;

	err = BleSetAdvData(adv_index, &config_adv_data);
	if (err) {
		XR_BLE_ERR("Failed to set advertising set data (%d)", err);
		return -ENOEXEC;
	}
	XR_BLE_DBG("Created adv id: %d, adv: %p", adv_index, adv);
	*advId = adv_index;
#else /* LEGACY_ADV */
	XR_BLE_DBG("%s,%d", __func__, __LINE__);
	int err;
	struct bt_le_adv_param adv_param = {};

	BleConfigAdvData config_adv_data;

	config_adv_data.advData = rawData.advData;
	config_adv_data.advLength = rawData.advDataLen;
	config_adv_data.scanRspData = rawData.rspData;
	config_adv_data.scanRspLength = rawData.rspDataLen;

	if (!OHOS_ADV_PARAM_2_XRBLE_LEGACY_ADV_PARAM(&param, &adv_param)) {
		XR_BLE_ERR("Failed to update advertiser set param (%d)", err);
		return -ENOEXEC;
	}
	err = BleStartAdv(0, &param);
	if (err) {
		XR_BLE_ERR("Failed to set advertising set data (%d)", err);
		return -ENOEXEC;
	}
	*advId = 0;

#endif /* CONFIG_BT_EXT_ADV */
#endif /* CONFIG_BT_BROADCASTER */
	return 0;
}

#endif /* CONFIG_BLEHOST */
